CDL Supports a number of nodal objects which are listed below. In each case there is a brief description of the object's functionality and a link to a full reference.
Large Symbols |
Small Symbols |
Arbitrated Stores
Arbitrated stores (ASTs) are used as repositories for persistent (state) data, and reads are therefore non-destructive. Arbitrated store buffers can be exclusively accessed by any number of readers, or a single writer, or a single updater. AST data provides an equivalent to object member data and/or static data. These objects also provide an alternative to conventional data locks. See Arbitrated Stores.
Transient Stores
Transient stores (TSTs) are used as repositories for transient (automatic) data. Each store contains a configurable number of buffers, and readers and writers are blocked if the store is empty or full respectively. Reads are destructive, but if distributed, the data is conserved until the last sharing reader completes (see Distributors). TST data therefore provides an equivalent to stack data (persists while referenced). See Transient Stores.
Counting Semaphores
CLiP's counting semaphores (CSMs) can be used as a direct equivalent to conventional counting semaphores; that is to say that one requester is unblocked for each signal delivered to the semaphore. They can also be designated as 'consuming semaphores' and in this mode, they will consume events from their designated provider, and then convert each event into a semaphore event (as though they had been signaled). In practice, these objects are seldom used. See Counting Semaphores.
Logical Semaphores
Logical semaphores (LSMs) contain a single signed integer which can be modified by signalers. Consumers can specify keys and rules. For example, the consumer may wish to block until the semaphore value exceeds 24, or is equal to 15 and so on. These objects are primarily provided as a means of providing switching and routing logic (equivalent to conditional branching). See Logical Semaphores.
Collectors
Collectors (CLXs) are one the most frequently used CDL objects, and can be thought of as logical AND gates. Any number of connections can be made to the collecting face (shown on left), and when all of the events have arrived, a single compound event is provided to the consuming object, which is connected to the providing face (shown on right). Collections are nestable in the sense that compound events can themselves be collected. In random mode, events are simultaneously requested and collected in arrival order; in sequential mode, events are collected in the direction indicated by the collection face indicator. Sequential collection is generally adopted for arbitrated stores that have blocking exclusion; this provides a means of avoiding deadly embraces. Compound events can be split back into their constituent parts by splitter objects (see below). See Collectors.
Competers
Competers (CPXs) are one of CDLs less frequently used objects. Most of the time multiple consumers share events that emanate from a single provider but occasionally the opposite is required and the application logic specifically requires that the consumers compete (farming out tasks to balance load etc). Each connected consumer competes for each event provided to the competer on a first come first serve basis. Distributors (see DBX below) can be thought of as the opposite of competers in that they ensure that all consumed events are shared by all connectors. In most cases competers are actually gratuitous because 'competing' is the default behavior for most objects that are not explicitly distributed. See Competers.
Distributors
Distributors (DBXs) are another frequently used CDL object and can be thought of as broadcasting each consumed event, to each connected consumer. The consumed event could be an atomic or compound event and remains open until the last consumer has indicated completion by closing. This provides CDL with an equivalent of automatic data and enables compose-able thread-safe communication by reference. See Distributors.
Demultiplexors
Demultiplexors (DMXs) are used to de-multiplex events that are provided by multiplexors (see MPX below). Note that multiplexed events can be passed through any arbitrary object tree (collected, split, distributed etc) and then de-multiplexed. This maintains the compose-ability of CDL circuitry. See Demultiplexors.
Multiplexors
Multiplexors (MPXs) can be thought of as logical OR gates, and any event retrieved by the consuming face (shown on left), is immediately delivered to the providing face (shown on right). As with all consuming objects, consumed events can be atomic or compounded. Multiplexors are frequently used as means of serializing parallel event streams or as an equivalents to 'WaitForMultipleObjects' or 'Select' functions. See Multiplexors.
Reducers
Reducers (RDXs) provide a means of selecting one in every N consumed events for delivery to their providing faces; all intermediary events are discarded. The period and phase of event delivery is configurable. These objects are generally associated with intrinsically concurrent applications. See Reducers.
Splitters
Splitters (SPXs) are used to split compound events that are provided by collectors (see CLX above). Note that compound events can be passed through any arbitrary object tree (re-collected, multiplexed, distributed etc) and then split. This maintains the compose-ability of CDL circuitry. See Splitters.
Call-backs
GUI call back functions (CBFs) are similar to circuit methods (see below) but are specifically provided as a portable interface between GUI and processing code. This avoids applications being locked-in to the details of particular message pumps such as those provided by Windows QT or MFC. The principal difference between CBFs and MTHDs is that the former execute within the GUI thread, and cannot be re-entered. See Call backs.
Methods
Circuit methods (MTHDs) are the principal repositories for application processing code. Unlike threads, where control is perceived to persist, circuit methods are scheduled. They execute and return (like GUI call-backs), and in so doing, automatically close their consumed event tree; releasing their interest in consumed resources, in the same manner that conventional functions execute returns and release automatic stack data. Closing the output leaves of the event tree, automatically propagates control to the next processing stage(s), and ensures that sequential functionality is repeatably reproduced; but in this case, in a concurrent processing domain.
Methods should always be used in preference to 'threads' because they provide almost identical functionality (preemptive asynchronous execution) but consume a small fraction of the resources required by conventional threads. They are also load-balanced across entire networks, whilst threads are only scheduled within a single process. See Methods.
Threads
CDL does support the notion of a thread (THRD) , but in practice they are only provided for special cases where applications need to perform external I/O in an iterative manner. Circuit methods make more efficient use of system resources, and since their implementation also avoids the expense of operating system context switching, threads are seldom used in practice. See Threads.
Devices
These support random and sequential mass storage devices, sockets, serial ports etc. These can be called from any active CDL object, but since they can block outside of CDL for indeterminate periods, are usually accessed by threads rather than methods. See Devices.
Interface Objects
Interface objects are provided as a means of accessing manual connections. The interface object name identifies an access function that will create and connect a manual connection of the interface object's specified type, and return a reference. This allows CDL circuitry to be called from any arbitrary application thread. In particular, they are used by GUI threads in order to access application circuitry. See Interface Objects.
Executable Timers
This executable object allows active objects (methods, call-backs and threads) to sleep until unblocked by an event from the timer object (ETMR). The object can be configured to generate periodic events at any frequency supported by the host operating system. If the sleep period is significant then over-all performance could be affected by the blocking of methods or call backs and so timer objects are typically associated with threads. Active timer objects are usually used by methods or threads because they avoid gratuitously blocking any physical threads. See Executable Timers.
Sink Objects
The sink object (SNK) is so-called because it will asynchronously consume from any event stream that it is connected to, and then discard the events. They are typically used to prevent dynamically connectable distributors from blocking, before they have any other connected consumers. They can also be used as a means of reducing collection latency by instigation collections whilst the collector's consumer is processing a retrieved event. They are also useful during development as a means of discarding 'as yet unhandled' event streams. See Sink Objects.
Circuits
The role of circuits in CDL is similar to the role of classes in object oriented languages, in that they localize and encapsulate program functionality. As with class definitions, that can contain aggregations of intrinsic objects and class instances (member objects), so circuit definitions can contain aggregations of intrinsic objects and sub-circuit instances. The major differences are that whilst class entry points are invoked by 'calling', circuit entry points are invoked by stimulation with 'events'. Also, circuits are intrinsically concurrent and will transparently distribute their execution across available processors. See Circuits.